// 手写promise
const PENGING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class Promise {
    constructor (executor) {
        try {
            executor(this.resolve, this.reject); // promise里传进来的执行器是立即执行的
        } catch (error) {
            this.reject(error);
        }
    }
    // promise状态
    status = PENGING;
    // 状态为fulfilled时的值
    successValue = undefined;
    // 状态为rejected时的值
    failValue = undefined;

    successCbs = [];
    failCbs= [];

    resolve = (value) => {
        if (this.status !== PENGING) return; // 如果状态不是pending，阻止程序向下执行
        this.status = FULFILLED; // 将状态改为成功
        this.successValue = value; // 保存成功之后的值
        while (this.successCbs.length) {
            this.successCbs.shift()();
        }
    }

    reject = (value) => {
        if (this.status !== PENGING) return;
        this.status = REJECTED;
        this.failValue = value;
        while (this.failCbs.length) {
            this.failCbs.shift()();
        }
    }

    then = (successCallback, failCallback) => { // 在then方法中可以判断promise的状态
        // 将then的参数变成可选参数,即使不传参状态也可以向后传递 promise.then().then(value=>value)
        successCallback = successCallback ? successCallback : value => value;
        failCallback = failCallback ? failCallback : err => {throw err}
        // then方法必须返回promise对象才能支持then的链式调用
        let nextThenPromise = new Promise((resolve, reject) => {
            // 同步操作->直接调用对应回调
            // this.status === FULFILLED && successCallback(this.successValue);
            if (this.status === FULFILLED) {
                setTimeout(()=>{ // 异步用来保证获取到nextThenPromise
                    try {
                        let nextThenValue = successCallback(this.successValue);
                        resolvePromise(nextThenPromise, nextThenValue, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                },0)
            } else if (this.status === REJECTED) {
                // failCallback(this.failValue);
                setTimeout(()=>{
                    try {
                        let nextThenValue = failCallback(this.failValue);
                        resolvePromise(nextThenPromise, nextThenValue, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                },0)
            } else {
                // 异步操作->这时状态是pending,将回调存储起来
                // this.successCbs.push(successCallback);
                // this.failCbs.push(failCallback);  
                setTimeout(()=>{
                    try {
                        this.successCbs.push(() => {
                            setTimeout(()=>{
                                try {
                                    let nextThenValue = successCallback(this.successValue);
                                    resolvePromise(nextThenPromise, nextThenValue, resolve, reject);
                                } catch (e) {
                                    reject(e);
                                }
                            },0)
                        });
                        this.failCbs.push(() => {
                            setTimeout(()=>{
                                try {
                                    let nextThenValue = failCallback(this.failValue);
                                    resolvePromise(nextThenPromise, nextThenValue, resolve, reject);
                                } catch (e) {
                                    reject(e);
                                }
                            },0)
                        });
                    } catch (e) {
                        reject(e);
                    }
                },0)
            }
        });
        return nextThenPromise;
    }

    finally (cb) {
        // 不管状态如何都会调用一次
        // 后面可以.then
        return this.then(value => { 
            return Promise.resolve(cb()).then(() => value);
        }, err => { 
            return Promise.resolve(cb()).then(() => {throw err});
        });
    }

    catch (failCallback) {
        return this.then(undefined, failCallback);
    }

    static all (array) {
        let result = [];
        let index = 0;
        return new Promise((resolve, reject) => {
            function add (key, value) {
                result[key] = value;
                index++;
                index === array.length && resolve(result);
            };
            for (let i = 0; i<array.length; i++) {
                if (array[i] instanceof Promise) {
                   array[i].then(value => add(i, value), err => reject(err));
                } else {
                    add(i, array[i]);;
                }
            }
        });
    }

    static resolve (value) { // 参数可以是普通值，也可以是promise对象
        if (value instanceof Promise) return value;
        return new Promise((resolve, reject) => {
            resolve(value);;
        });
    }
};

function resolvePromise (nextThenPromise, x, resolve, reject) {
    if (x === nextThenPromise) {
        return reject(new TypeError('错误，返回了自身promise'));
    }
    // 判断x是普通值还是promise
    // 如果是普通值直接resolve
    // 如果是promise对象，查看promise对象返回的结果
    // 根据promise对象返回的结果，决定调用resolve还是reject
    if (x instanceof Promise) {
        // x.then(res => resolve(res), err => reject(err));
        x.then(resolve, reject);
    } else {
        resolve(x);
    }
}


// const promise = new Promise((resolve, reject) => {
    // 1.测试同步操作
    // resolve('sucess');
    // reject('error');

    // 2.测试异步操作
    // setTimeout(() => {
    //     resolve('sucess');
    //     reject('error');
    // }, 2000);

    // 7.测试执行器报错
    // throw new error('executor error');
// });

// 3.测试调用多个then
// promise.then(successValue => {
//     console.log(successValue);
// }, failValue => {
//     console.log(failValue);
// });
// promise.then(successValue => {
//     console.log(successValue);
// }, failValue => {
//     console.log(failValue);
// });

// 4.测试链式调用--返回普通值
// promise.then((res)=>{
//     console.log(res);
//     return 100;
// }).then((res)=>{
//     console.log(res);
// }, err => console.log(err));

// 5.测试链式调用--返回promise对象
// promise.then((res)=>{
//     console.log(res);
//     return new Promise((resolve, reject)=>{
//         resolve(200);
//     });
// }).then((res)=>{
//     console.log(res);
// })

// 6.测试返回自身promise
// let p1 = promise.then((res)=>{
//     console.log(res);
//     return p1;
// });
// p1.then((res)=>{
//     console.log(res);
// }, (err)=>{
//     console.log(err);
// })

// 8.测试then报错
// promise.then((res)=>{
//     throw new error('then error');
//     console.log(res);
//     return 100;
// }).then((res)=>{
//     console.log(res);
// }, (err)=>{
//     console.log(err);
// })

// 9.测试then不传参 
// promise.then().then().then(res => console.log(res))

// 10.测试Promise.all
// let p1 = new Promise((resolve) => {resolve('p1')});
// let p2 = new Promise((resolve) => {
//     setTimeout(() => {
//         resolve('p2');
//     }, 2000);
// });
// Promise.all(['a', p1, p2, 'b']).then(result => console.log(result));

// 11.测试Promise.resolve
// let p1 = new Promise((resolve) => {resolve('p1')});
// Promise.resolve('100').then(value => console.log(value));
// Promise.resolve(p1).then(value => console.log(value));

// 12.测试Promise.finally
// let p1 = new Promise((resolve) => {resolve('p1')});
// p1.finally(()=>{
//     console.log('finally');
// }).then(value => console.log(value));

// 13.测试catch
// promise.then(value => console.log(value)).catch(err => console.log(err));
